package cn.wonderland.basic.service.impl;

import cn.wonderland.basic.cons.EmailRegistCon;
import cn.wonderland.basic.cons.PhoneRegistCon;
import cn.wonderland.basic.dto.EmailRegistDto;
import cn.wonderland.basic.dto.PhoneRegistDto;
import cn.wonderland.basic.service.VerifyCodeService;
import cn.wonderland.basic.util.*;
import cn.wonderland.user.domain.User;
import cn.wonderland.user.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class VerifyCodeServiceImpl implements VerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;


    // 生成图形验证码
    @Override
    public String getImageCode(String imageCodeKey) throws IOException {
        // 生成图形验证码
        String imageCode = VerifyCodeUtils.generateVerifyCode(1);
        // 将图形验证码存到redis中
        redisTemplate.opsForValue().set(imageCodeKey, imageCode, 3, TimeUnit.MINUTES);
        return VerifyCodeUtils.VerifyCode(80, 30, imageCode);
    }

    // 生成图形验证码--邮箱
    @Override
    public String getEmailImageCode(String emailImageCodeKey) throws IOException {
        // 生成图形验证码
        String imageCode = VerifyCodeUtils.generateVerifyCode(1);
        // 将图形验证码存到redis中
        redisTemplate.opsForValue().set(emailImageCodeKey, imageCode, 3, TimeUnit.MINUTES);
        return VerifyCodeUtils.VerifyCode(80, 30, imageCode);
    }


    /**
     * 获取短信验证码
     */
    @Override
    public void smsCode(PhoneRegistDto dto) {
        if ("binder".equals(dto.getType())) {
            // 发送手机短信验证码
            sendPhoneSms(dto, PhoneRegistCon.BINDER_REDIS_KEY);
        } else if ("register".equals(dto.getType())) {
            // 校验图形验证码
            verifyImageCode(dto);
            // 发送手机短信验证码
            sendPhoneSms(dto, PhoneRegistCon.REDIS_KEY);
        }
    }

    /**
     * 获取邮箱验证码
     */
    @Override
    public void emailCode(EmailRegistDto dto) {
        verifyEmailImageCode(dto);
        sendEmailCode(dto);
    }

    private void sendEmailCode(EmailRegistDto dto) {
        // 两次发送时间是否大于60s
        Long expire = redisTemplate.getExpire(String.format(EmailRegistCon.REDIS_KEY, dto.getEmail()));
        if (expire != null && expire >= (EmailRegistCon.REDIS_TTL - 1) * 60) {
            throw new BussinessException("请勿频繁获取邮箱验证码！");
        }
        // 判断输入的邮箱证码有没有超时，超时重置
        String emailCode = (String) redisTemplate.opsForValue()
                .get(String.format(EmailRegistCon.REDIS_KEY, dto.getEmail()));
        if (StringUtils.isBlank(emailCode)) {
            emailCode = StrUtils.getRandomString(4);
        }
        // 邮箱验证码使用Redis进行存储 设置3分钟超时
        redisTemplate.opsForValue().set(String.format(EmailRegistCon.REDIS_KEY, dto.getEmail())
                , emailCode, EmailRegistCon.REDIS_TTL, TimeUnit.MINUTES);
        // 发送邮件
//        MailUtils.sendMail(dto.getEmail(),"您的邮箱验证码是："+emailCode,"宠物之家验证信息");
        log.info("邮箱验证码是：{}", emailCode);
    }

    private void verifyEmailImageCode(EmailRegistDto dto) {
        // 非空校验
        // 判断图形验证码是否存在、是否正确
        String redisEmailImageCode = (String) redisTemplate.opsForValue().get(dto.getEmailImageCodeKey());
        if (StringUtils.isBlank(redisEmailImageCode) || !redisEmailImageCode.equalsIgnoreCase(dto.getEmailImageCodeValue())) {
            throw new BussinessException("图形验证码错误！");
        }

        // 判断邮箱号是否注册过 去user表中找是否存在
        User user = userMapper.findByEmail(dto.getEmail());
        if (user != null) {
            throw new BussinessException("该邮箱号已经注册过，请去登录！");
        }
        // 删除图形验证码
        redisTemplate.delete(dto.getEmailImageCodeKey());
    }

    // 发送手机短信验证码
    private void sendPhoneSms(PhoneRegistDto dto, String redisKey) {
        // 两次发送时间是否大于60s
        Long expire = redisTemplate.getExpire(String.format(redisKey, dto.getPhone()));
        if (expire != null && expire >= (PhoneRegistCon.REDIS_TTL - 1) * 60) {
            throw new BussinessException("请勿频繁获取短信验证码！");
        }
        redisTemplate.delete(String.format(redisKey, dto.getPhone())); // 清空 Redis 缓存
        // 判断输入的短信验证码有没有超时，超时重置
        String smsCode = (String) redisTemplate.opsForValue().get(String.format(redisKey, dto.getPhone()));
        if (StringUtils.isBlank(smsCode)){
            smsCode = StrUtils.getRandomString(4); // 验证码过期或者不存在就重新生成一个
        }
        // 发送短信
        log.info("手机短信验证码是：{}", smsCode);
        // 短信验证码使用Redis进行存储 设置3分钟超时
        redisTemplate.opsForValue().set(String.format(redisKey, dto.getPhone()), smsCode, PhoneRegistCon.REDIS_TTL, TimeUnit.MINUTES);

    }


    // 校验图形验证码
    private void verifyImageCode(PhoneRegistDto dto) {
        // 参数校验
        if (StringUtils.isBlank(dto.getImageCodeKey()) || StringUtils.isBlank(dto.getImageCodeValue())){
            throw new BussinessException("图形验证码或UUID不能为空！");
        }
        // 判断图形验证码是否存在、是否正确
        String redisImageCode = (String) redisTemplate.opsForValue().get(dto.getImageCodeKey());
        if (StringUtils.isBlank(redisImageCode) || !redisImageCode.equalsIgnoreCase(dto.getImageCodeValue())) {
            throw new BussinessException("图形验证码错误！");
        }
        // 判断手机号是否注册过 去user表中找是否存在
        User user = userMapper.findByPhone(dto.getPhone());
        if (user != null) {
            throw new BussinessException("该手机号已经注册过，请去登录！");
        }
        // 删除图形验证码
        redisTemplate.delete(dto.getImageCodeKey());
    }
}
